1 /* This is free and unencumbered software released into the public domain. */ 2 module lmdb_oo; 3 4 /** 5 * <lmdb_oo.d> - D wrapper for LMDB. 6 * 7 * @author Carsten Schlote <schlote@vahanus.net> 8 * @author Arto Bendiken <arto@bendiken.net> 9 * @see https://sourceforge.net/projects/lmdbxx/ 10 */ 11 12 import core.stdc.string; 13 import std.algorithm.mutation; 14 import std.conv; 15 import std.exception; 16 import std.stdio; 17 import std.string; 18 19 import lmdb; 20 21 alias mode = mdb_mode_t; 22 23 /* Exceptions for classes */ 24 25 /** Base class for LMDB exceptions */ 26 class MbdError : Exception { 27 /// 28 mixin basicExceptionCtors; 29 /** 30 * Throws an MbdError based on the given LMDB return code. 31 */ 32 static void raise(string origin, int rc) { 33 string msg = origin; msg ~= "(" ~ fromStringz(mdb_strerror(rc)) ~ ")"; 34 switch (rc) { 35 case MDB_KEYEXIST: 36 throw new KeyExistError(origin); 37 case MDB_NOTFOUND: 38 throw new NotFoundError(origin); 39 case MDB_CORRUPTED: 40 throw new CorruptedError(origin); 41 case MDB_PANIC: 42 throw new PanicError(origin); 43 case MDB_VERSION_MISMATCH: 44 throw new VersionMismatchError(origin); 45 case MDB_MAP_FULL: 46 throw new MapFullError(origin); 47 case MDB_BAD_DBI: 48 throw new BadDbiError(origin); 49 default: 50 throw new RuntimeError(origin); 51 } 52 } 53 } 54 55 /** Base class for logic error conditions. */ 56 class LogicError : MbdError { 57 public: 58 /** Constructor */ 59 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 60 super(msg, file, line, next); 61 } 62 } 63 64 /** Base class for fatal error conditions. */ 65 class FatalError : MbdError { 66 public: 67 /** Constructor */ 68 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 69 super(msg, file, line, next); 70 } 71 } 72 73 /** Base class for runtime error conditions. */ 74 class RuntimeError : MbdError { 75 public: 76 /** Constructor */ 77 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 78 super(msg, file, line, next); 79 } 80 } 81 82 /** Exception class for `MDB_KEYEXIST` errors. 83 * @see http://symas.com/mdb/doc/group__errors.html#ga05dc5bbcc7da81a7345bd8676e8e0e3b 84 */ 85 final class KeyExistError : RuntimeError { 86 public: 87 /** Constructor */ 88 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 89 super(msg, file, line, next); 90 } 91 } 92 93 /** Exception class for `MDB_NOTFOUND` errors. 94 * @see http://symas.com/mdb/doc/group__errors.html#gabeb52e4c4be21b329e31c4add1b71926 95 */ 96 final class NotFoundError : RuntimeError { 97 public: 98 /** Constructor */ 99 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 100 super(msg, file, line, next); 101 } 102 } 103 104 /** Exception class for `MDB_CORRUPTED` errors. 105 * @see http://symas.com/mdb/doc/group__errors.html#gaf8148bf1b85f58e264e57194bafb03ef 106 */ 107 final class CorruptedError : FatalError { 108 public: 109 /** Constructor */ 110 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 111 super(msg, file, line, next); 112 } 113 } 114 115 /** Exception class for `MDB_PANIC` errors. 116 * @see http://symas.com/mdb/doc/group__errors.html#gae37b9aedcb3767faba3de8c1cf6d3473 117 */ 118 final class PanicError : FatalError { 119 public: 120 /** Constructor */ 121 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 122 super(msg, file, line, next); 123 } 124 } 125 126 /** Exception class for `MDB_VERSION_MISMATCH` errors. 127 * @see http://symas.com/mdb/doc/group__errors.html#ga909b2db047fa90fb0d37a78f86a6f99b 128 */ 129 final class VersionMismatchError : FatalError { 130 public: 131 /** Constructor */ 132 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 133 super(msg, file, line, next); 134 } 135 } 136 137 /** Exception class for `MDB_MAP_FULL` errors. 138 * @see http://symas.com/mdb/doc/group__errors.html#ga0a83370402a060c9175100d4bbfb9f25 139 */ 140 final class MapFullError : RuntimeError { 141 public: 142 /** Constructor */ 143 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 144 super(msg, file, line, next); 145 } 146 } 147 148 /** Exception class for `MDB_BAD_DBI` errors. 149 * @since 0.9.14 (2014/09/20) 150 * @see http://symas.com/mdb/doc/group__errors.html#gab4c82e050391b60a18a5df08d22a7083 151 */ 152 final class BadDbiError : RuntimeError { 153 public: 154 /** Constructor */ 155 pure nothrow @nogc @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 156 super(msg, file, line, next); 157 } 158 } 159 160 161 /* ------------------------------------------------------------------ */ 162 163 /* Procedural Interface: Metadata */ 164 165 // TODO: mdb_version() 166 // TODO: mdb_strerror() 167 168 169 /* Procedural Interface: Environment */ 170 171 // TODO: mdb_env_set_assert() 172 // TODO: mdb_reader_list() 173 // TODO: mdb_reader_check() 174 175 /** Wrapper for mdb_env_create 176 * @throws lmdb_oo.error on failure 177 * @see http://symas.com/mdb/doc/group__mdb.html#gaad6be3d8dcd4ea01f8df436f41d158d4 178 */ 179 static void env_create(MDB_env** env) { 180 const int rc = mdb_env_create(env); 181 if (rc != MDB_SUCCESS) { 182 MbdError.raise("mdb_env_create", rc); 183 } 184 } 185 186 /** Wrapper for mdb_env_open 187 * @throws lmdb_oo.MbdError on failure 188 * @see http://symas.com/mdb/doc/group__mdb.html#ga32a193c6bf4d7d5c5d579e71f22e9340 189 */ 190 static void env_open(MDB_env* env, const char* path, const uint flags, const mode mode) { 191 const int rc = mdb_env_open(env, path, flags, mode); 192 if (rc != MDB_SUCCESS) { 193 MbdError.raise("mdb_env_open", rc); 194 } 195 } 196 197 /** Wrapper for mdb_env_copy 198 * @throws lmdb_oo.MbdError on failure 199 * @see http://symas.com/mdb/doc/group__mdb.html#ga3bf50d7793b36aaddf6b481a44e24244 200 * @see http://symas.com/mdb/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378 201 */ 202 static void env_copy(MDB_env* env, const char* path, const uint flags = 0) { 203 const int rc = mdb_env_copy2(env, path, flags); 204 if (rc != MDB_SUCCESS) { 205 MbdError.raise("mdb_env_copy2", rc); 206 } 207 } 208 209 /** Wrapper for mdb_env_copy_fd 210 * @throws lmdb_oo.MbdError on failure 211 * @see http://symas.com/mdb/doc/group__mdb.html#ga5040d0de1f14000fa01fc0b522ff1f86 212 * @see http://symas.com/mdb/doc/group__mdb.html#ga470b0bcc64ac417de5de5930f20b1a28 213 */ 214 static void env_copy_fd(MDB_env* env, const mdb_filehandle_t fd, const uint flags = 0) { 215 const int rc = mdb_env_copyfd2(env, fd, flags); 216 if (rc != MDB_SUCCESS) { 217 MbdError.raise("mdb_env_copyfd2", rc); 218 } 219 } 220 221 /** Wrapper for mdb_env_stat 222 * @throws lmdb_oo.MbdError on failure 223 * @see http://symas.com/mdb/doc/group__mdb.html#gaf881dca452050efbd434cd16e4bae255 224 */ 225 static void env_stat(MDB_env* env, MDB_stat* stat) { 226 const int rc = mdb_env_stat(env, stat); 227 if (rc != MDB_SUCCESS) { 228 MbdError.raise("mdb_env_stat", rc); 229 } 230 } 231 232 /** Wrapper for env_info 233 * @throws lmdb_oo.MbdError on failure 234 * @see http://symas.com/mdb/doc/group__mdb.html#ga18769362c7e7d6cf91889a028a5c5947 235 */ 236 static void env_info(MDB_env* env, MDB_envinfo* stat) { 237 const int rc = mdb_env_info(env, stat); 238 if (rc != MDB_SUCCESS) { 239 MbdError.raise("mdb_env_info", rc); 240 } 241 } 242 243 /** Wrapper for mdb_env_sync 244 * @throws lmdb_oo.MbdError on failure 245 * @see http://symas.com/mdb/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037 246 */ 247 static void env_sync(MDB_env* env, const bool force = true) { 248 const int rc = mdb_env_sync(env, force); 249 if (rc != MDB_SUCCESS) { 250 MbdError.raise("mdb_env_sync", rc); 251 } 252 } 253 254 /** Wrapper for mdb_env_close 255 * @see http://symas.com/mdb/doc/group__mdb.html#ga4366c43ada8874588b6a62fbda2d1e95 256 */ 257 static void env_close(MDB_env* env) nothrow { 258 mdb_env_close(env); 259 } 260 261 /** Wrapper for mdb_env_set_flags 262 * @throws lmdb_oo.MbdError on failure 263 * @see http://symas.com/mdb/doc/group__mdb.html#ga83f66cf02bfd42119451e9468dc58445 264 */ 265 static void env_set_flags(MDB_env* env, const uint flags, const bool onoff = true) { 266 const int rc = mdb_env_set_flags(env, flags, onoff ? 1 : 0); 267 if (rc != MDB_SUCCESS) { 268 MbdError.raise("mdb_env_set_flags", rc); 269 } 270 } 271 272 /** Wrapper for mdb_env_get_flags 273 * @throws lmdb_oo.MbdError on failure 274 * @see http://symas.com/mdb/doc/group__mdb.html#ga2733aefc6f50beb49dd0c6eb19b067d9 275 */ 276 static void env_get_flags(MDB_env* env, uint* flags) { 277 const int rc = mdb_env_get_flags(env, flags); 278 if (rc != MDB_SUCCESS) { 279 MbdError.raise("mdb_env_get_flags", rc); 280 } 281 } 282 283 /** Wrapper for mdb_env_get_path 284 * @throws lmdb_oo.MbdError on failure 285 * @see http://symas.com/mdb/doc/group__mdb.html#gac699fdd8c4f8013577cb933fb6a757fe 286 */ 287 static void env_get_path(MDB_env* env, const char** path) { 288 const int rc = mdb_env_get_path(env, path); 289 if (rc != MDB_SUCCESS) { 290 MbdError.raise("mdb_env_get_path", rc); 291 } 292 } 293 294 /** Wrapper for mdb_env_get_fd 295 * @throws lmdb_oo.MbdError on failure 296 * @see http://symas.com/mdb/doc/group__mdb.html#gaf1570e7c0e5a5d860fef1032cec7d5f2 297 */ 298 static void env_get_fd(MDB_env* env, mdb_filehandle_t* fd) { 299 const int rc = mdb_env_get_fd(env, fd); 300 if (rc != MDB_SUCCESS) { 301 MbdError.raise("mdb_env_get_fd", rc); 302 } 303 } 304 305 /** Wrapper for mdb_env_set_mapsize 306 * @throws lmdb_oo.MbdError on failure 307 * @see http://symas.com/mdb/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5 308 */ 309 static void env_set_mapsize(MDB_env* env, const size_t size) { 310 const int rc = mdb_env_set_mapsize(env, size); 311 if (rc != MDB_SUCCESS) { 312 MbdError.raise("mdb_env_set_mapsize", rc); 313 } 314 } 315 316 /** Wrapper for mdb_env_set_max_readers 317 * @throws lmdb_oo.MbdError on failure 318 * @see http://symas.com/mdb/doc/group__mdb.html#gae687966c24b790630be2a41573fe40e2 319 */ 320 static void env_set_max_readers(MDB_env* env, const uint count) { 321 const int rc = mdb_env_set_maxreaders(env, count); 322 if (rc != MDB_SUCCESS) { 323 MbdError.raise("mdb_env_set_maxreaders", rc); 324 } 325 } 326 327 /** Wrapper for mdb_env_get_max_readers 328 * @throws lmdb_oo.MbdError on failure 329 * @see http://symas.com/mdb/doc/group__mdb.html#ga70e143cf11760d869f754c9c9956e6cc 330 */ 331 static void env_get_max_readers(MDB_env* env, uint* count) { 332 const int rc = mdb_env_get_maxreaders(env, count); 333 if (rc != MDB_SUCCESS) { 334 MbdError.raise("mdb_env_get_maxreaders", rc); 335 } 336 } 337 338 /** Wrapper for mdb_env_set_max_dbs 339 * @throws lmdb_oo.MbdError on failure 340 * @see http://symas.com/mdb/doc/group__mdb.html#gaa2fc2f1f37cb1115e733b62cab2fcdbc 341 */ 342 static void env_set_max_dbs(MDB_env* env, const MDB_dbi count) { 343 const int rc = mdb_env_set_maxdbs(env, count); 344 if (rc != MDB_SUCCESS) { 345 MbdError.raise("mdb_env_set_maxdbs", rc); 346 } 347 } 348 349 /** Wrapper for mdb_env_get_max_keysize 350 * @see http://symas.com/mdb/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94 351 */ 352 static uint env_get_max_keysize(MDB_env* env) { 353 const int rc = mdb_env_get_maxkeysize(env); 354 assert(rc >= 0); 355 return cast(uint) rc; 356 } 357 358 /** Wrapper for mdb_env_set_userctx 359 * @throws lmdb_oo.MbdError on failure 360 * @since 0.9.11 (2014/01/15) 361 * @see http://symas.com/mdb/doc/group__mdb.html#gaf2fe09eb9c96eeb915a76bf713eecc46 362 */ 363 static void env_set_userctx(MDB_env* env, void* ctx) { 364 const int rc = mdb_env_set_userctx(env, ctx); 365 if (rc != MDB_SUCCESS) { 366 MbdError.raise("mdb_env_set_userctx", rc); 367 } 368 } 369 370 /** Wrapper for mdb_env_get_userctx 371 * @since 0.9.11 (2014/01/15) 372 * @see http://symas.com/mdb/doc/group__mdb.html#ga45df6a4fb150cda2316b5ae224ba52f1 373 */ 374 static void* env_get_userctx(MDB_env* env) { 375 return mdb_env_get_userctx(env); 376 } 377 378 379 /* Procedural Interface: Transactions */ 380 381 /** Wrapper for mdb_txn_begin 382 * @throws lmdb_oo.MbdError on failure 383 * @see http://symas.com/mdb/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920 384 */ 385 static void txn_begin(MDB_env* env, MDB_txn* parent, const uint flags, MDB_txn** txn) { 386 const int rc = mdb_txn_begin(env, parent, flags, txn); 387 if (rc != MDB_SUCCESS) { 388 MbdError.raise("mdb_txn_begin", rc); 389 } 390 } 391 392 /** Wrapper for mdb_txn_env 393 * @see http://symas.com/mdb/doc/group__mdb.html#gaeb17735b8aaa2938a78a45cab85c06a0 394 */ 395 static MDB_env* txn_env(MDB_txn* txn) nothrow { 396 return mdb_txn_env(txn); 397 } 398 399 /** Wrapper for mdb_txn_id 400 * @note Only available in HEAD, not yet in any 0.9.x release (as of 0.9.16). 401 */ 402 static size_t txn_id(MDB_txn* txn) nothrow { 403 return mdb_txn_id(txn); 404 } 405 406 /** Wrapper for mdb_txn_commit 407 * @throws lmdb_oo.MbdError on failure 408 * @see http://symas.com/mdb/doc/group__mdb.html#ga846fbd6f46105617ac9f4d76476f6597 409 */ 410 static void txn_commit(MDB_txn* txn) { 411 const int rc = mdb_txn_commit(txn); 412 if (rc != MDB_SUCCESS) { 413 MbdError.raise("mdb_txn_commit", rc); 414 } 415 } 416 417 /** Wrapper for mdb_txn_abort 418 * @see http://symas.com/mdb/doc/group__mdb.html#ga73a5938ae4c3239ee11efa07eb22b882 419 */ 420 static void txn_abort(MDB_txn* txn) nothrow { 421 mdb_txn_abort(txn); 422 } 423 424 /** Wrapper for mdb_txn_reset 425 * @see http://symas.com/mdb/doc/group__mdb.html#ga02b06706f8a66249769503c4e88c56cd 426 */ 427 static void txn_reset(MDB_txn* txn) nothrow { 428 mdb_txn_reset(txn); 429 } 430 431 /** Wrapper for mdb_txn_renew 432 * @throws lmdb_oo.MbdError on failure 433 * @see http://symas.com/mdb/doc/group__mdb.html#ga6c6f917959517ede1c504cf7c720ce6d 434 */ 435 static void txn_renew(MDB_txn* txn) { 436 const int rc = mdb_txn_renew(txn); 437 if (rc != MDB_SUCCESS) { 438 MbdError.raise("mdb_txn_renew", rc); 439 } 440 } 441 442 443 /* Procedural Interface: Databases */ 444 445 /** Wrapper for mdb_dbi_open 446 * @throws lmdb_oo.MbdError on failure 447 * @see http://symas.com/mdb/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a 448 */ 449 static void dbi_open(MDB_txn* txn, const char* name, const uint flags, MDB_dbi* dbi) { 450 const int rc = mdb_dbi_open(txn, name, flags, dbi); 451 if (rc != MDB_SUCCESS) { 452 MbdError.raise("mdb_dbi_open", rc); 453 } 454 } 455 456 /** Wrapper for mdb_stat 457 * @throws lmdb_oo.MbdError on failure 458 * @see http://symas.com/mdb/doc/group__mdb.html#gae6c1069febe94299769dbdd032fadef6 459 */ 460 static void dbi_stat(MDB_txn* txn, const MDB_dbi dbi, MDB_stat* result) { 461 const int rc = mdb_stat(txn, dbi, result); 462 if (rc != MDB_SUCCESS) { 463 MbdError.raise("mdb_stat", rc); 464 } 465 } 466 467 /** Wrapper for mdb_flags 468 * @throws lmdb_oo.MbdError on failure 469 * @see http://symas.com/mdb/doc/group__mdb.html#ga95ba4cb721035478a8705e57b91ae4d4 470 */ 471 static void dbi_flags(MDB_txn* txn, const MDB_dbi dbi, uint* flags) { 472 const int rc = mdb_dbi_flags(txn, dbi, flags); 473 if (rc != MDB_SUCCESS) { 474 MbdError.raise("mdb_dbi_flags", rc); 475 } 476 } 477 478 /** Wrapper for mdb_close 479 * @see http://symas.com/mdb/doc/group__mdb.html#ga52dd98d0c542378370cd6b712ff961b5 480 */ 481 static void dbi_close(MDB_env* env, const MDB_dbi dbi) nothrow { 482 mdb_dbi_close(env, dbi); 483 } 484 485 /** Wrapper for mdb_drop 486 * @see http://symas.com/mdb/doc/group__mdb.html#gab966fab3840fc54a6571dfb32b00f2db 487 */ 488 static void dbi_drop(MDB_txn* txn, const MDB_dbi dbi, const bool del = false) { 489 const int rc = mdb_drop(txn, dbi, del ? 1 : 0); 490 if (rc != MDB_SUCCESS) { 491 MbdError.raise("mdb_drop", rc); 492 } 493 } 494 495 /** Wrapper for mdb_set_compare 496 * @throws lmdb_oo.MbdError on failure 497 * @see http://symas.com/mdb/doc/group__mdb.html#ga68e47ffcf72eceec553c72b1784ee0fe 498 */ 499 static void dbi_set_compare(MDB_txn* txn, const MDB_dbi dbi, MDB_cmp_func* cmp = null) { 500 const int rc = mdb_set_compare(txn, dbi, cmp); 501 if (rc != MDB_SUCCESS) { 502 MbdError.raise("mdb_set_compare", rc); 503 } 504 } 505 506 /** Wrapper for mdb_set_dupsort 507 * @throws lmdb_oo.MbdError on failure 508 * @see http://symas.com/mdb/doc/group__mdb.html#gacef4ec3dab0bbd9bc978b73c19c879ae 509 */ 510 static void dbi_set_dupsort(MDB_txn* txn, const MDB_dbi dbi, MDB_cmp_func* cmp = null) { 511 const int rc = mdb_set_dupsort(txn, dbi, cmp); 512 if (rc != MDB_SUCCESS) { 513 MbdError.raise("mdb_set_dupsort", rc); 514 } 515 } 516 517 /** Wrapper for mdb_set_relfunc 518 * @throws lmdb_oo.MbdError on failure 519 * @see http://symas.com/mdb/doc/group__mdb.html#ga697d82c7afe79f142207ad5adcdebfeb 520 */ 521 static void dbi_set_relfunc(MDB_txn* txn, const MDB_dbi dbi, MDB_rel_func* rel) { 522 const int rc = mdb_set_relfunc(txn, dbi, rel); 523 if (rc != MDB_SUCCESS) { 524 MbdError.raise("mdb_set_relfunc", rc); 525 } 526 } 527 528 /** Wrapper for mdb_dbi_set_relctx 529 * @throws lmdb_oo.MbdError on failure 530 * @see http://symas.com/mdb/doc/group__mdb.html#ga7c34246308cee01724a1839a8f5cc594 531 */ 532 static void dbi_set_relctx(MDB_txn* txn, const MDB_dbi dbi, void* ctx) { 533 const int rc = mdb_set_relctx(txn, dbi, ctx); 534 if (rc != MDB_SUCCESS) { 535 MbdError.raise("mdb_set_relctx", rc); 536 } 537 } 538 539 /** Wrapper for mdb_get 540 * @retval true if the key/value pair was retrieved 541 * @retval false if the key wasn't found 542 * @see http://symas.com/mdb/doc/group__mdb.html#ga8bf10cd91d3f3a83a34d04ce6b07992d 543 */ 544 static bool dbi_get(MDB_txn* txn, const MDB_dbi dbi, const MDB_val* key, MDB_val* data) { 545 const int rc = mdb_get(txn, cast(uint) dbi, cast(MDB_val*) key, data); 546 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) { 547 MbdError.raise("mdb_get", rc); 548 } 549 return (rc == MDB_SUCCESS); 550 } 551 552 /** Wrapper for mdb_put 553 * @retval true if the key/value pair was inserted 554 * @retval false if the key already existed 555 * @see http://symas.com/mdb/doc/group__mdb.html#ga4fa8573d9236d54687c61827ebf8cac0 556 */ 557 static bool dbi_put(MDB_txn* txn, MDB_dbi dbi, MDB_val* key, MDB_val* data, uint flags = 0) { 558 const int rc = mdb_put(txn, dbi, key, data, flags); 559 if (rc != MDB_SUCCESS && rc != MDB_KEYEXIST) { 560 MbdError.raise("mdb_put", rc); 561 } 562 return (rc == MDB_SUCCESS); 563 } 564 565 /** Wrapper for mdb_del 566 * @retval true if the key/value pair was removed 567 * @retval false if the key wasn't found 568 * @see http://symas.com/mdb/doc/group__mdb.html#gab8182f9360ea69ac0afd4a4eaab1ddb0 569 */ 570 static bool dbi_del(MDB_txn* txn, MDB_dbi dbi, MDB_val* key, MDB_val* data = null) { 571 const int rc = mdb_del(txn, dbi, key, data); 572 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) { 573 MbdError.raise("mdb_del", rc); 574 } 575 return (rc == MDB_SUCCESS); 576 } 577 578 579 /* -- Procedural Interface: Cursors --------------------------------- */ 580 581 /** Wrapper for cursor_open 582 * @throws lmdb_oo.MbdError on failure 583 */ 584 static void cursor_open(MDB_txn* txn, const MDB_dbi dbi, MDB_cursor** cursor) { 585 const int rc = mdb_cursor_open(txn, dbi, cursor); 586 if (rc != MDB_SUCCESS) { 587 MbdError.raise("mdb_cursor_open", rc); 588 } 589 } 590 591 /** Wrapper for cursor_close 592 * @see http://symas.com/mdb/doc/group__mdb.html#gad685f5d73c052715c7bd859cc4c05188 593 */ 594 static void cursor_close(MDB_cursor* cursor) nothrow { 595 mdb_cursor_close(cursor); 596 } 597 598 /** Wrapper for cursor_renew 599 * @throws lmdb_oo.MbdError on failure 600 * @see http://symas.com/mdb/doc/group__mdb.html#gac8b57befb68793070c85ea813df481af 601 */ 602 static void cursor_renew(MDB_txn* txn, MDB_cursor* cursor) { 603 const int rc = mdb_cursor_renew(txn, cursor); 604 if (rc != MDB_SUCCESS) { 605 MbdError.raise("mdb_cursor_renew", rc); 606 } 607 } 608 609 /** Wrapper for cursor_txn 610 * @see http://symas.com/mdb/doc/group__mdb.html#ga7bf0d458f7f36b5232fcb368ebda79e0 611 */ 612 static MDB_txn* cursor_txn(MDB_cursor* cursor) nothrow { 613 return mdb_cursor_txn(cursor); 614 } 615 616 /** Wrapper for cursor_dbi 617 * @see http://symas.com/mdb/doc/group__mdb.html#ga2f7092cf70ee816fb3d2c3267a732372 618 */ 619 static MDB_dbi cursor_dbi(MDB_cursor* cursor) nothrow { 620 return mdb_cursor_dbi(cursor); 621 } 622 623 /** Wrapper for cursor_get 624 * @throws lmdb_oo.MbdError on failure 625 * @see http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0 626 */ 627 static bool cursor_get(MDB_cursor* cursor, MDB_val* key, MDB_val* data, const MDB_cursor_op op) { 628 const int rc = mdb_cursor_get(cursor, key, data, op); 629 if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) { 630 MbdError.raise("mdb_cursor_get", rc); 631 } 632 return (rc == MDB_SUCCESS); 633 } 634 635 /** Wrapper for cursor_put 636 * @throws lmdb_oo.MbdError on failure 637 * @see http://symas.com/mdb/doc/group__mdb.html#ga1f83ccb40011837ff37cc32be01ad91e 638 */ 639 static void cursor_put(MDB_cursor* cursor, MDB_val* key, MDB_val* data, const uint flags = 0) { 640 const int rc = mdb_cursor_put(cursor, key, data, flags); 641 if (rc != MDB_SUCCESS) { 642 MbdError.raise("mdb_cursor_put", rc); 643 } 644 } 645 646 /** Wrapper for cursor_del 647 * @throws lmdb_oo.MbdError on failure 648 * @see http://symas.com/mdb/doc/group__mdb.html#ga26a52d3efcfd72e5bf6bd6960bf75f95 649 */ 650 static void cursor_del(MDB_cursor* cursor, const uint flags = 0) { 651 const int rc = mdb_cursor_del(cursor, flags); 652 if (rc != MDB_SUCCESS) { 653 MbdError.raise("mdb_cursor_del", rc); 654 } 655 } 656 657 /** Wrapper for cursor_count 658 * @throws lmdb_oo.MbdError on failure 659 * @see http://symas.com/mdb/doc/group__mdb.html#ga4041fd1e1862c6b7d5f10590b86ffbe2 660 */ 661 static void cursor_count(MDB_cursor* cursor, ref size_t count) { 662 const int rc = mdb_cursor_count(cursor, &count); 663 if (rc != MDB_SUCCESS) { 664 MbdError.raise("mdb_cursor_count", rc); 665 } 666 } 667 668 669 /* Resource Interface: Values */ 670 671 /** Wrapper class for `MDB_val` structures. 672 * 673 * @note Instances of this class are movable and copyable both. 674 * @see std.algorithm.mutation 675 * @see http://symas.com/mdb/doc/group__mdb.html#structMDB__val 676 */ 677 class MdbVal { 678 protected: 679 MDB_val _val; 680 681 public: 682 /** Default constructor. */ 683 this() nothrow { 684 } 685 686 /** Constructor. Expects a D string */ 687 this(const string data) nothrow { 688 this(toStringz(data), data.sizeof); 689 } 690 691 /** Constructor. Expects a C-string as input. */ 692 this(const char* data) nothrow { 693 this(data, strlen(data)); 694 } 695 696 /** Constructor. Expects some data and size */ 697 this(const void* data, const size_t size) nothrow { 698 _val = MDB_val(data, size); 699 } 700 701 /** Constructor. Use a pointer to other object for a shallow copy */ 702 this(MdbVal* data) nothrow { 703 _val = MDB_val(&data._val); 704 } 705 706 /** Constructor. Use a reference to a object to do a deep copy */ 707 this(ref MdbVal data) nothrow { 708 _val = data._val; // Triggers copy-constructor of struct dupping the data. 709 } 710 711 /** Determines whether this value is empty. */ 712 bool empty() const nothrow { 713 return _val.size() == 0; 714 } 715 716 /** Returns the size of the data. */ 717 size_t size() const nothrow { 718 return _val.size(); 719 } 720 721 /** Returns a pointer to the embedded struct */ 722 T* data(T)() nothrow { 723 return _val.data(T)(); 724 } 725 726 /** Assigns the value. */ 727 MdbVal assign(const ref string data) nothrow { 728 return assign(toStringz(data), data.sizeof); 729 } 730 /** Assigns the value. */ 731 MdbVal assign(const char* data) nothrow { 732 return assign(data, strlen(data)); 733 } 734 /** Assigns the value. */ 735 MdbVal assign(T)(const T* data, const size_t size) nothrow { 736 _val.mv_size = size; 737 _val.mv_data = cast(void*) data; 738 return this; 739 } 740 741 /** Print it some useful way... */ 742 override string toString() const { 743 import std.format : format; 744 return format("%x @ %d %s", _val.data!(ubyte*)(), _val.size(), _val.data!ubyte()[0.._val.size()]); 745 } 746 } 747 748 //static assert(std::is_pod<lmdb_oo.MdbVal>::value, "MdbVal must be a POD type"); 749 //static assert((lmdb_oo.MdbVal.sizeof) == (lmdb.MDB_val.sizeof), "sizeof(lmdb_oo.MdbVal) != sizeof(MDB_val)"); 750 751 752 /* Resource Interface: Environment */ 753 754 /** 755 * Resource class for `MDB_env*` handles. 756 * 757 * @note Instances of this class are movable, but not copyable. 758 * @see http://symas.com/mdb/doc/group__internal.html#structMDB__env 759 */ 760 class MdbEnv { 761 protected: 762 MDB_env* _handle; 763 764 public: 765 static uint default_flags; ///< Default flags 766 static mode default_mode = std.conv.octal!644; /**< -rw-r--r-- */ 767 768 /** 769 * Creates a new LMDB environment. 770 * 771 * @param flags 772 * @throws lmdb_oo.MbdError on failure 773 */ 774 static MdbEnv create(const uint flags = default_flags) { 775 MDB_env* handle; 776 env_create(&handle); 777 778 assert(handle != null); 779 780 if (flags) { 781 try { 782 env_set_flags(handle, flags); 783 } catch (const MbdError) { 784 env_close(handle); 785 throw new Exception("Problem opeing env"); 786 } 787 } 788 return new MdbEnv(handle); 789 } 790 791 /** 792 * Constructor. 793 * 794 * @param handle a valid `MDB_env*` handle 795 */ 796 this(MDB_env* handle) nothrow { 797 _handle = handle; 798 } 799 800 /** 801 * Move constructor. 802 */ 803 //this(MdbEnv&& other) nothrow { 804 // std::swap(_handle, other._handle); 805 //} 806 807 /** 808 * Move assignment operator. 809 */ 810 //MdbEnv& operator=(MdbEnv&& other) nothrow { 811 // if (this != &other) { 812 // std::swap(_handle, other._handle); 813 // } 814 // return *this; 815 //} 816 817 /** 818 * Destructor. 819 */ 820 ~this() nothrow { 821 try { 822 close(); 823 } catch (Exception ex) { 824 } 825 } 826 827 /** 828 * Returns the underlying `MDB_env*` handle. 829 */ 830 //operator MDB_env*() const nothrow { 831 // return _handle; 832 //} 833 834 /** 835 * Returns the underlying `MDB_env*` handle. 836 */ 837 MDB_env* handle() const nothrow { 838 return cast(MDB_env*) _handle; 839 } 840 841 /** 842 * Flushes data buffers to disk. 843 * 844 * @param force 845 * @throws lmdb_oo.MbdError on failure 846 */ 847 void sync(const bool force = true) { 848 env_sync(handle(), force); 849 } 850 851 /** 852 * Closes this environment, releasing the memory map. 853 * 854 * @note this method is idempotent 855 * @post `handle() == null` 856 */ 857 void close() nothrow { 858 if (handle()) { 859 env_close(handle()); 860 _handle = null; 861 } 862 } 863 864 /** 865 * Opens this environment. 866 * 867 * @param path 868 * @param flags 869 * @param mode 870 * @throws lmdb_oo.MbdError on failure 871 */ 872 MdbEnv open(const char* path, const uint flags = default_flags, const mode mode = default_mode) { 873 env_open(handle(), path, flags, mode); 874 return this; 875 } 876 877 /** 878 * @param flags 879 * @param onoff 880 * @throws lmdb_oo.MbdError on failure 881 */ 882 MdbEnv set_flags(const uint flags, const bool onoff = true) { 883 env_set_flags(handle(), flags, onoff); 884 return this; 885 } 886 887 /** 888 * @param size 889 * @throws lmdb_oo.MbdError on failure 890 */ 891 MdbEnv set_mapsize(const size_t size) { 892 env_set_mapsize(handle(), size); 893 return this; 894 } 895 896 /** 897 * @param count 898 * @throws lmdb_oo.MbdError on failure 899 */ 900 MdbEnv set_max_readers(const uint count) { 901 env_set_max_readers(handle(), count); 902 return this; 903 } 904 905 /** 906 * @param count 907 * @throws lmdb_oo.MbdError on failure 908 */ 909 MdbEnv set_max_dbs(const MDB_dbi count) { 910 env_set_max_dbs(handle(), count); 911 return this; 912 } 913 } 914 915 916 /* Resource Interface: Transactions */ 917 918 /** 919 * Resource class for `MDB_txn*` handles. 920 * 921 * @note Instances of this class are movable, but not copyable. 922 * @see http://symas.com/mdb/doc/group__internal.html#structMDB__txn 923 */ 924 class MdbTxn { 925 protected: 926 MDB_txn* _handle; 927 928 public: 929 static uint default_flags; ///< Default flags 930 931 /** 932 * Creates a new LMDB transaction. 933 * 934 * @param env the environment handle 935 * @param parent 936 * @param flags 937 * @throws lmdb_oo.MbdError on failure 938 */ 939 static MdbTxn begin(MDB_env* env, MDB_txn* parent = null, const uint flags = default_flags) { 940 MDB_txn* handle; 941 txn_begin(env, parent, flags, &handle); 942 assert(handle != null); 943 return new MdbTxn(handle); 944 } 945 946 /** 947 * Constructor. 948 * 949 * @param handle a valid `MDB_txn*` handle 950 */ 951 this(MDB_txn* handle) nothrow { 952 _handle = handle; 953 } 954 955 /** 956 * Destructor. 957 */ 958 ~this() nothrow { 959 if (_handle) { 960 try { 961 abort(); 962 } catch (Exception ex) { 963 } 964 _handle = null; 965 } 966 } 967 968 /** 969 * Returns the underlying `MDB_txn*` handle. 970 */ 971 MDB_txn* opUnary(string s)() if (s == "*") { 972 return _handle; 973 } 974 975 /** 976 * Returns the underlying `MDB_txn*` handle. 977 */ 978 MDB_txn* handle() nothrow { 979 return _handle; 980 } 981 982 /** 983 * Returns the transaction's `MDB_env*` handle. 984 */ 985 MDB_env* env() nothrow { 986 return txn_env(handle()); 987 } 988 989 /** 990 * Commits this transaction. 991 * 992 * @throws lmdb_oo.MbdError on failure 993 * @post `handle() == null` 994 */ 995 void commit() { 996 txn_commit(_handle); 997 _handle = null; 998 } 999 1000 /** 1001 * Aborts this transaction. 1002 * 1003 * @post `handle() == null` 1004 */ 1005 void abort() nothrow { 1006 txn_abort(_handle); 1007 _handle = null; 1008 } 1009 1010 /** 1011 * Resets this read-only transaction. 1012 */ 1013 void reset() nothrow { 1014 txn_reset(_handle); 1015 } 1016 1017 /** 1018 * Renews this read-only transaction. 1019 * 1020 * @throws lmdb_oo.MbdError on failure 1021 */ 1022 void renew() { 1023 txn_renew(_handle); 1024 } 1025 } 1026 1027 1028 /* Resource Interface: Databases */ 1029 1030 /** 1031 * Resource class for `MDB_dbi` handles. 1032 * 1033 * @note Instances of this class are movable, but not copyable. 1034 * @see http://symas.com/mdb/doc/group__mdb.html#gadbe68a06c448dfb62da16443d251a78b 1035 */ 1036 class MdbDbi { 1037 protected: 1038 MDB_dbi _handle; 1039 1040 public: 1041 static uint default_flags; ///< Default flags 1042 static uint default_put_flags; ///< Default flags 1043 1044 /** Opens a database handle. 1045 * 1046 * @param txn the transaction handle 1047 * @param name 1048 * @param flags 1049 * @throws lmdb_oo.MbdError on failure 1050 */ 1051 static MdbDbi open(MDB_txn* txn, const char* name = null, const uint flags = default_flags) { 1052 MDB_dbi handle; 1053 mdb_dbi_open(txn, name, flags, &handle); 1054 return new MdbDbi(handle); 1055 } 1056 /** Close a database handle 1057 * Param: 1058 * env = an MdbEnv 1059 */ 1060 void close(MdbEnv env) { 1061 mdb_dbi_close(env.handle(), _handle); 1062 } 1063 1064 /** Constructor. 1065 * Param: handle = a valid `MDB_dbi` handle 1066 */ 1067 this(const MDB_dbi handle) nothrow { 1068 _handle = handle; 1069 } 1070 1071 /** 1072 * Destructor. 1073 */ 1074 ~this() nothrow { 1075 if (_handle) { 1076 /* No need to call close() here. */ 1077 } 1078 } 1079 1080 /** 1081 * Returns the underlying `MDB_dbi` handle. 1082 */ 1083 MDB_dbi handle() nothrow { 1084 return _handle; 1085 } 1086 1087 /** 1088 * Returns statistics for this database. 1089 * 1090 * @param txn a transaction handle 1091 * @throws lmdb_oo.MbdError on failure 1092 */ 1093 MDB_stat stat(MDB_txn* txn) { 1094 MDB_stat result; 1095 dbi_stat(txn, handle(), &result); 1096 return result; 1097 } 1098 1099 /** 1100 * Retrieves the flags for this database handle. 1101 * 1102 * @param txn a transaction handle 1103 * @throws lmdb_oo.MbdError on failure 1104 */ 1105 uint flags(MDB_txn* txn) { 1106 uint result; 1107 dbi_flags(txn, handle(), &result); 1108 return result; 1109 } 1110 1111 /** 1112 * Returns the number of records in this database. 1113 * 1114 * @param txn a transaction handle 1115 * @throws lmdb_oo.MbdError on failure 1116 */ 1117 size_t size(MDB_txn* txn) { 1118 return stat(txn).ms_entries; 1119 } 1120 1121 /** 1122 * @param txn a transaction handle 1123 * @param del 1124 * @throws lmdb_oo.MbdError on failure 1125 */ 1126 void drop(MDB_txn* txn, const bool del = false) { 1127 dbi_drop(txn, handle(), del); 1128 } 1129 1130 /** 1131 * Sets a custom key comparison function for this database. 1132 * 1133 * @param txn a transaction handle 1134 * @param cmp the comparison function 1135 * @throws lmdb_oo.MbdError on failure 1136 */ 1137 MdbDbi set_compare(MDB_txn* txn, MDB_cmp_func* cmp = null) { 1138 dbi_set_compare(txn, handle(), cmp); 1139 return this; 1140 } 1141 1142 /** 1143 * Retrieves a key/value pair from this database. 1144 * 1145 * @param txn a transaction handle 1146 * @param key 1147 * @param data 1148 * @throws lmdb_oo.MbdError on failure 1149 */ 1150 bool get(MDB_txn* txn, const ref MdbVal key, ref MdbVal data) { 1151 return dbi_get(txn, handle(), &key._val, &data._val); 1152 } 1153 1154 /** 1155 * Retrieves a key from this database. 1156 * 1157 * @param txn a transaction handle 1158 * @param key 1159 * @throws lmdb_oo.MbdError on failure 1160 */ 1161 bool get(K)(MDB_txn* txn, const ref K key) const { 1162 const MdbVal k = new MdbVal(key, sizeof(K)); 1163 MdbVal v = new MdbVal(); 1164 return dbi_get(txn, handle(), k, v); 1165 } 1166 1167 /** 1168 * Retrieves a key/value pair from this database. 1169 * 1170 * @param txn a transaction handle 1171 * @param key 1172 * @param val 1173 * @throws lmdb_oo.MbdError on failure 1174 */ 1175 bool get(K, V)(MDB_txn* txn, const ref K key, ref V val) const { 1176 const MdbVal k = new MdbVal(&key, sizeof(K)); 1177 MdbVal v = new MdbVal(); 1178 const bool result = dbi_get(txn, handle(), k, v); 1179 if (result) { 1180 val = *v.data(V)(); 1181 } 1182 return result; 1183 } 1184 1185 /** 1186 * Retrieves a key/value pair from this database. 1187 * 1188 * @param txn a transaction handle 1189 * @param key a NUL-terminated string key 1190 * @param val 1191 * @throws lmdb_oo.MbdError on failure 1192 */ 1193 bool get(V)(MDB_txn* txn, const char* key, ref V val) const { 1194 const MdbVal k = new MdbVal(key, strlen(key)); 1195 MdbVal v = new MdbVal(); 1196 const bool result = dbi_get(txn, handle(), k, v); 1197 if (result) { 1198 val = *v.data(V); 1199 } 1200 return result; 1201 } 1202 1203 /** 1204 * Stores a key/value pair into this database. 1205 * 1206 * @param txn a transaction handle 1207 * @param key 1208 * @param data 1209 * @param flags 1210 * @throws lmdb_oo.MbdError on failure 1211 */ 1212 bool put(MDB_txn* txn, const ref MdbVal key, ref MdbVal data, const uint flags = default_put_flags) { 1213 return dbi_put(txn, handle(), cast(MDB_val*)&key._val, cast(MDB_val*) &data._val, flags); 1214 } 1215 1216 /** 1217 * Stores a key into this database. 1218 * 1219 * @param txn a transaction handle 1220 * @param key 1221 * @param flags 1222 * @throws lmdb_oo.MbdError on failure 1223 */ 1224 bool put(K)(MDB_txn* txn, const ref K key, const uint flags = default_put_flags) { 1225 const MdbVal k = new MdbVal(&key, sizeof(K)); 1226 MdbVal v = new MdbVal(); 1227 return dbi_put(txn, handle(), k, v, flags); 1228 } 1229 1230 /** 1231 * Stores a key/value pair into this database. 1232 * 1233 * @param txn a transaction handle 1234 * @param key 1235 * @param val 1236 * @param flags 1237 * @throws lmdb_oo.MbdError on failure 1238 */ 1239 bool put(K, V)(MDB_txn* txn, const ref K key, const ref V val, 1240 const uint flags = default_put_flags) { 1241 const MdbVal k = new MdbVal(&key, sizeof(K)); 1242 MdbVal v = new MdbVal(&val, sizeof(V)); 1243 return dbi_put(txn, handle(), k, v, flags); 1244 } 1245 1246 /** 1247 * Stores a key/value pair into this database. 1248 * 1249 * @param txn a transaction handle 1250 * @param key a NUL-terminated string key 1251 * @param val 1252 * @param flags 1253 * @throws lmdb_oo.MbdError on failure 1254 */ 1255 bool put(V)(MDB_txn* txn, const char* key, const ref V val, const uint flags = default_put_flags) { 1256 const MdbVal k = new MdbVal(key, strlen(key)); 1257 MdbVal v = new MdbVal(&val, sizeof(V)); 1258 return dbi_put(txn, handle(), k, v, flags); 1259 } 1260 1261 /** 1262 * Stores a key/value pair into this database. 1263 * 1264 * @param txn a transaction handle 1265 * @param key a NUL-terminated string key 1266 * @param val a NUL-terminated string key 1267 * @param flags 1268 * @throws lmdb_oo.MbdError on failure 1269 */ 1270 bool put(MDB_txn* txn, const char* key, const char* val, const uint flags = default_put_flags) { 1271 const MdbVal k = new MdbVal(key, strlen(key)); 1272 MdbVal v = new MdbVal(val, strlen(val)); 1273 return dbi_put(txn, handle(), cast(MDB_val*)&k._val, cast(MDB_val*)&v._val, flags); 1274 } 1275 1276 /** 1277 * Removes a key/value pair from this database. 1278 * 1279 * @param txn a transaction handle 1280 * @param key 1281 * @throws lmdb_oo.MbdError on failure 1282 */ 1283 bool del(MDB_txn* txn, const ref MdbVal key) { 1284 return dbi_del(txn, handle(), cast(MDB_val*)&key._val); 1285 } 1286 1287 /** 1288 * Removes a key/value pair from this database. 1289 * 1290 * @param txn a transaction handle 1291 * @param key 1292 * @throws lmdb_oo.MbdError on failure 1293 */ 1294 bool del(K)(MDB_txn* txn, const ref K key) { 1295 const MdbVal k = new MdbVal(&key, sizeof(K)); 1296 return dbi_del(txn, handle(), k); 1297 } 1298 } 1299 1300 1301 /* Resource Interface: Cursors */ 1302 1303 /** Resource class for `MDB_cursor*` handles. 1304 * 1305 * @note Instances of this class are movable, but not copyable. 1306 * @see http://symas.com/mdb/doc/group__internal.html#structMDB__cursor 1307 */ 1308 class MdbCursor { 1309 protected: 1310 MDB_cursor* _handle; ///< Opace handle from lmdb library 1311 1312 public: 1313 static uint default_flags; ///< Default cursor flags for ops 1314 1315 /** Creates an LMDB MdbCursor. 1316 * @param txn the transaction handle 1317 * @param dbi the database handle 1318 * @throws lmdb_oo.MbdError on failure 1319 */ 1320 static MdbCursor open(MDB_txn* txn, const MDB_dbi dbi) { 1321 MDB_cursor* handle; 1322 cursor_open(txn, dbi, &handle); 1323 assert(handle != null); 1324 return new MdbCursor(handle); 1325 } 1326 1327 /** Constructor. 1328 * @param handle a valid `MDB_cursor*` handle 1329 */ 1330 this(MDB_cursor* handle) nothrow { 1331 _handle = handle; 1332 } 1333 1334 /** Destructor. 1335 */ 1336 ~this() nothrow { 1337 try { 1338 close(); 1339 } catch (Exception ex) { 1340 writefln("Catched a exception '%s'", ex.msg); 1341 } 1342 } 1343 1344 /** Returns the underlying `MDB_cursor*` handle. 1345 */ 1346 MDB_cursor* handle() nothrow { 1347 return _handle; 1348 } 1349 1350 /** Closes this cursor. 1351 * @note this method is idempotent 1352 * @post `handle() == null` 1353 */ 1354 void close() nothrow { 1355 if (_handle) { 1356 cursor_close(_handle); 1357 _handle = null; 1358 } 1359 } 1360 1361 /** Renews this cursor. 1362 * 1363 * @param txn the transaction scope 1364 * @throws lmdb_oo.MbdError on failure 1365 */ 1366 void renew(MDB_txn* txn) { 1367 cursor_renew(txn, handle()); 1368 } 1369 1370 /** Returns the cursor's transaction handle. 1371 */ 1372 MDB_txn* txn() nothrow { 1373 return cursor_txn(cast(MDB_cursor*)handle()); 1374 } 1375 1376 /** Returns the cursor's database handle. 1377 */ 1378 MDB_dbi dbi() nothrow { 1379 return cursor_dbi(cast(MDB_cursor*)handle()); 1380 } 1381 1382 /** Retrieves a key from the database. 1383 * 1384 * @param key 1385 * @param op 1386 * @throws lmdb_oo.MbdError on failure 1387 */ 1388 bool get(MDB_val* key, const MDB_cursor_op op) { 1389 return get(key, null, op); 1390 } 1391 1392 /** Retrieves a key from the database. 1393 * 1394 * @param key 1395 * @param op 1396 * @throws lmdb_oo.MbdError on failure 1397 */ 1398 bool get(ref MdbVal key, const MDB_cursor_op op) { 1399 return get(cast(MDB_val*)&key._val, cast(MDB_val*)null, op); 1400 } 1401 1402 /** Retrieves a key/value pair from the database. 1403 * 1404 * @param key 1405 * @param val (may be `null`) 1406 * @param op 1407 * @throws lmdb_oo.MbdError on failure 1408 */ 1409 bool get(MDB_val* key, MDB_val* val, const MDB_cursor_op op) { 1410 return cursor_get(handle(), key, val, op); 1411 } 1412 1413 /** Retrieves a key/value pair from the database. 1414 * 1415 * @param key 1416 * @param val 1417 * @param op 1418 * @throws lmdb_oo.MbdError on failure 1419 */ 1420 bool get(ref MdbVal key, ref MdbVal val, const MDB_cursor_op op) { 1421 return cursor_get(handle(), cast(MDB_val*)&key._val, cast(MDB_val*)&val._val, op); 1422 } 1423 1424 /** Retrieves a key/value pair from the database. 1425 * 1426 * @param key 1427 * @param val 1428 * @param op 1429 * @throws lmdb_oo.MbdError on failure 1430 */ 1431 bool get(ref string key, ref string val, const MDB_cursor_op op) { 1432 MdbVal k = new MdbVal(), v = new MdbVal(); 1433 const bool found = get(k, v, op); 1434 if (found) { 1435 char[] key0; key0 ~= to!(char[])(k._val.mv_data [ 0 .. k._val.mv_size]); 1436 key = to!string(key0); 1437 char[] val0; val0 ~= to!(char[])(v._val.mv_data [ 0 .. v._val.mv_size]); 1438 val = to!string(val0); 1439 } 1440 return found; 1441 } 1442 1443 /** Positions this cursor at the given key. 1444 * 1445 * @param key 1446 * @param op 1447 * @throws lmdb_oo.MbdError on failure 1448 */ 1449 bool find(K)(const ref K key, const MDB_cursor_op op = MDB_SET) { 1450 MdbVal k = new MdbVal(&key, sizeof(K)); 1451 return get(k, null, op); 1452 } 1453 }